/*
 * File     : AbstractPlatform.java
 * Created  : 16 Apr 2011
 * Revision : $Revision$
 *
 * Copyright © 2006-9 Matthew Wilson (mj. {my-surname} .uk {at} gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.dni.internal.platform;

import java.util.Map;
import java.util.Set;

import com.googlecode.dni.CallingConvention;
import com.googlecode.dni.Padding;
import com.googlecode.dni.internal.library.DynamicLibrary;
import com.googlecode.dni.platform.PlatformGroup;
import com.googlecode.dni.platform.PlatformType;
import com.googlecode.dni.type.Pointer;


/**
 * <p>
 *  Base implementation of {@link Platform}.
 * </p>
 *
 * @author Matthew Wilson
 */
abstract class AbstractPlatform implements Platform
{

    private final PlatformGroup platformGroup;

    private final PlatformType platformType;

    private final DynamicLibrary dniDynamicLibrary;

    private final Padding defaultPadding;

    private final Set< CallingConvention > supportedCallingConventions;

    private final CallingConvention defaultCallingConvention;

    private Map< Class< ? >, Integer > nativeSizes;

    private int pageSize;


    /**
     * @param platformGroup
     *            the platform group
     * @param platformType
     *            the platform type
     * @param dniDynamicLibrary
     *            the DNI dynamic library
     * @param defaultPadding
     *            the default padding
     * @param supportedCallingConventions
     *            the supported calling conventions
     * @param defaultCallingConvention
     *            the default calling conventions
     */
    AbstractPlatform( final PlatformGroup platformGroup,
                      final PlatformType platformType,
                      final DynamicLibrary dniDynamicLibrary,
                      final Padding defaultPadding,
                      final Set< CallingConvention > supportedCallingConventions,
                      final CallingConvention defaultCallingConvention )
    {
        this.platformGroup = platformGroup;
        this.platformType = platformType;
        this.dniDynamicLibrary = dniDynamicLibrary;
        this.defaultPadding = defaultPadding;
        this.supportedCallingConventions = supportedCallingConventions;
        this.defaultCallingConvention = defaultCallingConvention;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final PlatformGroup getPlatformGroup()
    {
        return this.platformGroup;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final PlatformType getPlatformType()
    {
        return this.platformType;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final DynamicLibrary getDniDynamicLibrary()
    {
        return this.dniDynamicLibrary;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final Map< Class< ? >, Integer > getNativeSizes()
    {
        Map< Class< ? >, Integer > nativeSizesLocal = this.nativeSizes;
        if ( nativeSizesLocal == null )
        {
            nativeSizesLocal = PlatformUtilities.getNativeSizes();
            this.nativeSizes = nativeSizesLocal;
        }
        return this.nativeSizes;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final Padding getDefaultPadding()
    {
        return this.defaultPadding;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final String getDefaultCharset()
    {
        // TODO
        throw new UnsupportedOperationException( "TODO" );
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final Set< CallingConvention > getSupportedCallingConventions()
    {
        return this.supportedCallingConventions;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final CallingConvention getDefaultCallingConvention()
    {
        return this.defaultCallingConvention;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final int getPageSize()
    {
        int local = this.pageSize;
        if ( local == 0 )
        {
            local = PlatformUtilities.getPageSize();
            this.pageSize = local;
        }
        return local;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final Pointer allocatePages( final int size, final boolean executable )
    {
        long address = PlatformUtilities.allocatePages( size, executable );
        if ( address == 0 )
        {
            throw new OutOfMemoryError( "Cannot allocate pages" );
        }
        return new Pointer( address );
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void unallocatePages( final Pointer pointer, final int size )
    {
        PlatformUtilities.unallocatePages( pointer.getAddress(), size );
    }

}
